package postgres

import (
	auth "auth/model/entity"
	"context"
	manager "manager/model/entity"
	"time"
)

var UserCount = &user{}
var UserBindBike = &userBindBike{}
var UserUnbindBike = &userUnbindBike{}
var UserComplain = &userComplain{}
var UserActive = &userActive{}

type user struct {
}

type userBindBike struct {
}
type userUnbindBike struct {
}
type userComplain struct {
}
type userActive struct {
}

// Count 绑定车辆
func (e *userBindBike) Count(ctx context.Context) (int64, error) {

	var (
		err           error
		bindUserCount int64
	)
	err = GetManagerDB(ctx).Model(&manager.UserEbike{}).
		Where("is_manager=?", 1).Distinct("user_id").Count(&bindUserCount).Error
	if err != nil {
		return 0, err
	}
	return bindUserCount, err
}

func (e *userBindBike) CountByRange(ctx context.Context, begin, end time.Time) (DurationCount, error) {
	var (
		count DurationCount
		err   error
	)
	count.Point = begin
	err = GetManagerDB(ctx).Raw("SELECT COUNT(DISTINCT(user_id)) "+
		"from user_ebikes "+
		"where is_manager = 1 and created_at > ? and created_at < ?", begin.Unix(), end.Unix()).Row().Scan(&count.Count)
	if err != nil {
		return DurationCount{}, nil
	}
	return count, err
}

// ThirtyDaysCount 时间节点所在的月份30天的数据
func (e *userBindBike) ThirtyDaysCount(ctx context.Context, month time.Time) (DurationCounts, error) {

	rawSql := "SELECT DATE_TRUNC('day', to_timestamp(created_at)) AS day, COUNT(DISTINCT(user_id)) " +
		"from user_ebikes " +
		"where is_manager = 1  and created_at > ? and created_at < ? group by day"
	begin := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
	end := time.Date(month.Year(), month.Month()+1, 1, 0, 0, 0, 0, month.Location())
	var total int64
	_ = GetManagerDB(ctx).Model(&manager.UserEbike{}).Where("is_manager=1 and created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetManagerDB(ctx), rawSql, begin, end, total)
}

// TwelveMonthsCount 时间所在年份12个月的数据
func (e *userBindBike) TwelveMonthsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('month', to_timestamp(created_at)) AS month, COUNT(DISTINCT(user_id)) " +
		"from user_ebikes " +
		"where is_manager = 1  and created_at > ? and created_at < ? group by month"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())
	var total int64
	_ = GetManagerDB(ctx).Model(&manager.UserEbike{}).Where("is_manager=1 and created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetManagerDB(ctx), rawSql, begin, end, total)
}

// FiveYearsCount 最近五年的数据
func (e *userBindBike) FiveYearsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('year', to_timestamp(created_at)) AS year, COUNT(DISTINCT(user_id)) " +
		"from user_ebikes " +
		"where is_manager = 1  and created_at > ? and created_at < ? group by year"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())
	var total int64
	_ = GetManagerDB(ctx).Model(&manager.UserEbike{}).Where("is_manager=1 and created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetManagerDB(ctx), rawSql, begin, end, total)
}

// User 求当前服务器用户总数量
func (u *user) User(ctx context.Context) (int64, error) {
	var (
		err       error
		userCount int64
	)
	err = GetAuthDB(ctx).Model(&auth.User{}).Count(&userCount).Error
	if err != nil {
		return 0, err
	}
	return userCount, err
}

// ShareUser 当前有分享过车辆用户
func (u *user) ShareUser(ctx context.Context) (int64, error) {
	var (
		count int64
		err   error
	)
	err = GetManagerDB(ctx).Model(&manager.ShareEbike{}).Distinct("user_id").Count(&count).Error
	if err != nil {
		return 0, err
	}
	return count, err
}

// Count 用户总数
func (e *user) Count(ctx context.Context) (int64, error) {
	var (
		err       error
		userCount int64
	)
	err = GetAuthDB(ctx).Model(&auth.User{}).Count(&userCount).Error
	if err != nil {
		return 0, err
	}
	return userCount, err
}

func (e *user) CountByRange(ctx context.Context, begin, end time.Time) (DurationCount, error) {
	var (
		count DurationCount
		err   error
	)

	err = GetAuthDB(ctx).Model(&auth.User{}).
		Where("created_at > ? and created_at < ?", begin.Unix(), end.Unix()).Count(&count.Count).Error
	count.Point = begin
	if err != nil {
		return DurationCount{}, nil
	}
	return count, err
}

// ThirtyDaysCount 时间节点所在的月份30天的数据,求总量，不求分量，
func (e *user) ThirtyDaysCount(ctx context.Context, month time.Time) (DurationCounts, error) {

	rawSql := "SELECT DATE_TRUNC('day', to_timestamp(created_at)) AS day, COUNT(1) " +
		"from users where created_at > ? and created_at < ? group by day"
	begin := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
	end := time.Date(month.Year(), month.Month()+1, 1, 0, 0, 0, 0, month.Location())
	var total int64
	_ = GetAuthDB(ctx).Model(&auth.User{}).Where("created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetAuthDB(ctx), rawSql, begin, end, total)
}

// TwelveMonthsCount 时间所在年份12个月的数据
func (e *user) TwelveMonthsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('month', to_timestamp(created_at)) AS month, COUNT(1) " +
		"from users where created_at > ? and created_at < ? group by month"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())

	var total int64
	_ = GetAuthDB(ctx).Model(&auth.User{}).Where("created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetAuthDB(ctx), rawSql, begin, end, total)
}

// FiveYearsCount 最近五年的数据
func (e *user) FiveYearsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('year', to_timestamp(created_at)) AS year, COUNT(1) " +
		"from users where created_at > ? and created_at < ? group by year"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())
	var total int64
	_ = GetAuthDB(ctx).Model(&auth.User{}).Where("created_at<?", begin.Unix()).Count(&total).Error
	return queryCountWithTotal(GetAuthDB(ctx), rawSql, begin, end, total)
}

// Count 新增用户，没有绑定用车
func (e *userUnbindBike) Count(ctx context.Context) (int64, error) {
	var (
		err           error
		bindUserCount int64
	)
	err = GetManagerDB(ctx).Model(&manager.UserEbike{}).
		Where("is_manager=?", 0).Distinct("user_id").Count(&bindUserCount).Error
	if err != nil {
		return 0, err
	}
	return bindUserCount, err
}

func (e *userUnbindBike) CountByRange(ctx context.Context, begin, end time.Time) (DurationCount, error) {
	var (
		count DurationCount
		err   error
	)
	total, err := UserCount.CountByRange(ctx, begin, end)
	bind, err := UserBindBike.CountByRange(ctx, begin, end)
	if err != nil {
		return count, err
	}
	count.Point = total.Point
	count.Count = total.Count - bind.Count
	return count, err
}

// ThirtyDaysCount 时间节点所在的月份30天的数据
func (e *userUnbindBike) ThirtyDaysCount(ctx context.Context, month time.Time) (DurationCounts, error) {
	var (
		counts DurationCounts
		err    error
	)
	total, err := UserCount.ThirtyDaysCount(ctx, month)
	bind, err := UserBindBike.ThirtyDaysCount(ctx, month)
	if err != nil {
		return counts, err
	}
	for i := 0; i < len(total); i++ {
		var count DurationCount
		count.Point = total[i].Point
		count.Count = total[i].Count - bind[i].Count
		counts = append(counts, count)
	}
	return counts, err
}

// TwelveMonthsCount 时间所在年份12个月的数据
func (e *userUnbindBike) TwelveMonthsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	var (
		counts DurationCounts
		err    error
	)
	total, err := UserCount.TwelveMonthsCount(ctx, year)
	bind, err := UserBindBike.TwelveMonthsCount(ctx, year)
	if err != nil {
		return counts, err
	}
	for i := 0; i < len(total); i++ {
		var count DurationCount
		count.Point = total[i].Point
		count.Count = total[i].Count - bind[i].Count
		counts = append(counts, count)
	}
	return counts, err
}

// FiveYearsCount 最近五年的数据
func (e *userUnbindBike) FiveYearsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	var (
		counts DurationCounts
		err    error
	)
	total, err := UserCount.FiveYearsCount(ctx, year)
	bind, err := UserBindBike.FiveYearsCount(ctx, year)
	if err != nil {
		return counts, err
	}
	for i := 0; i < len(total); i++ {
		var count DurationCount
		count.Point = total[i].Point
		count.Count = total[i].Count - bind[i].Count
		counts = append(counts, count)
	}
	return counts, err
}

// Count 用户投诉
func (e *userComplain) Count(ctx context.Context) (int64, error) {
	var (
		count int64
		err   error
	)
	err = GetManagerDB(ctx).Model(&manager.Feedback{}).Count(&count).Error
	if err != nil {
		return 0, err
	}
	return count, err
}

func (e *userComplain) CountByRange(ctx context.Context, begin, end time.Time) (DurationCount, error) {
	var (
		count DurationCount
		err   error
	)
	count.Point = begin
	err = GetManagerDB(ctx).Model(&manager.Feedback{}).Where("created_at > ? and created_at < ?",
		begin.Unix(), end.Unix()).Count(&count.Count).Error
	if err != nil {
		return DurationCount{}, err
	}
	return count, err
}

// ThirtyDaysCount 时间节点所在的月份30天的数据
func (e *userComplain) ThirtyDaysCount(ctx context.Context, month time.Time) (DurationCounts, error) {

	rawSql := "SELECT DATE_TRUNC('day', to_timestamp(created_at)) AS day, COUNT(1) FROM feedbacks " +
		"where created_at > ? and created_at < ?  group by day"
	begin := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
	end := time.Date(month.Year(), month.Month()+1, 1, 0, 0, 0, 0, month.Location())
	return queryCount(GetManagerDB(ctx), rawSql, begin, end)
}

// TwelveMonthsCount 时间所在年份12个月的数据
func (e *userComplain) TwelveMonthsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('month', to_timestamp(created_at)) AS month, COUNT(1) FROM feedbacks " +
		"where created_at > ? and created_at < ?  group by month"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())
	return queryCount(GetManagerDB(ctx), rawSql, begin, end)
}

// FiveYearsCount 最近五年的数据
func (e *userComplain) FiveYearsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	rawSql := "SELECT DATE_TRUNC('year', to_timestamp(created_at)) AS year, COUNT(1) FROM feedbacks " +
		"where created_at > ? and created_at < ?  group by year"
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	end := time.Date(year.Year(), 12, 30, 0, 0, 0, 0, year.Location())
	return queryCount(GetManagerDB(ctx), rawSql, begin, end)
}

func (u *user) UseBikeUserIncrease(ctx context.Context, dur string, begin, end int64) ([]DurationCount, error) {
	var (
		month []DurationCount
		err   error
	)
	rows, err := GetManagerDB(ctx).Raw("SELECT DATE_TRUNC('"+dur+"', to_timestamp(created_at)) AS day, COUNT(1) from cycling_recodes "+
		"where created_at > ? and created_at < ? GROUP BY day ORDER BY day ;", begin, end).Rows()
	defer rows.Close()
	for rows.Next() {
		var record DurationCount
		rows.Scan(&record.Point, &record.Count)
		month = append(month, record)
	}
	if err != nil {
		return nil, err
	}
	return month, err
}

// 按天获取当前月份每日数据
func (u *user) UseBikeUserIncreaseMonth(ctx context.Context, timestamp int64) ([]DurationCount, error) {
	begin, end := monthDuration(timestamp)
	return u.UseBikeUserIncrease(ctx, "day", begin, end)
}

// 以月为维度获取一年的数据
func (u *user) UseBikeUserIncreaseYear(ctx context.Context, timestamp int64) ([]DurationCount, error) {
	end := time.Unix(timestamp, 0)
	begin := time.Date(end.Year(), 1, 1, 0, 0, 0, 0, end.Location())
	return u.UseBikeUserIncrease(ctx, "month", begin.Unix(), end.Unix())
}

// 计算时间月份的每日数据
// 例如 timestamp是2023年5月3号，就会将五月份到昨日为止每日的数量计算出来返回
func (u *user) GetUseCountByMonth(ctx context.Context, timestamp int64) ([]DurationCount, error) {
	var (
		month  []DurationCount
		record DurationCount
		err    error
	)
	begin, end := monthDuration(timestamp)
	rows, err := GetAuthDB(ctx).Raw("SELECT DATE_TRUNC('day', to_timestamp(created_at)) AS day, COUNT(1) from users "+
		"where created_at > ? and created_at < ? GROUP BY day ORDER BY day ;", begin, end).Rows()
	defer rows.Close()
	if rows.Next() {
		rows.Scan(&record.Point, &record.Count)
		month = append(month, record)
	}
	if err != nil {
		return nil, err
	}
	return month, err
}

// 计算给定时间月份区间的timestamp
func monthDuration(timestamp int64) (begin int64, end int64) {
	now := time.Now()
	given := time.Unix(timestamp, 0)
	// 先看是不是同一个月份
	begin = time.Date(given.Year(), given.Month(), 1, 0, 0, 0, 0, now.Location()).Unix()
	// 不再同一个月份
	if given.Month() != now.Month() || given.Year() != now.Year() {
		end = time.Date(given.Year(), given.Month()+1, 1, 0, 0, 0, 0, now.Location()).Unix()
	} else {
		// 不包含当天
		end = time.Date(given.Year(), given.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Unix()
	}
	return
}

func (a *userActive) Count(ctx context.Context) (int64, error) {
	return 0, nil
}

func (a *userActive) CountByRange(ctx context.Context, begin, end time.Time) (DurationCount, error) {
	var (
		count DurationCount
		err   error
	)
	row := GetAuthDB(ctx).Raw("select sum(total) from user_active where created_at>? and created_at < ?", begin.Unix(), end.Unix()).Row()
	row.Scan(&count.Count)
	count.Point = begin
	return count, err
}

func (a *userActive) ThirtyDaysCount(ctx context.Context, month time.Time) (DurationCounts, error) {
	var (
		err  error
		etys []auth.UserActive
	)
	begin := time.Date(month.Year(), month.Month(), 1, 0, 0, 0, 0, month.Location())
	end := time.Date(month.Year(), month.Month()+1, 1, 0, 0, 0, 0, month.Location())
	err = GetAuthDB(ctx).Where("year=? and month=?", month.Year(), month.Month()).Find(&etys).Error
	days := end.YearDay() - begin.YearDay()
	counts := make(DurationCounts, days)
	for i := 0; i < days; i++ {
		day := begin.AddDate(0, 0, i)
		counts[i] = DurationCount{
			Point: day,
			Count: 0,
		}
		for _, ety := range etys {
			if int64(day.Year()) == ety.Year && int64(day.Month()) == ety.Month && int64(day.Day()) == ety.Day {
				counts[i].Count = ety.Total
			}
		}
	}
	return counts, err
}

func (a *userActive) TwelveMonthsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	var (
		err  error
		etys []auth.UserActive
	)
	err = GetAuthDB(ctx).Where("year=? ", year.Year()).Find(&etys).Error
	begin := time.Date(year.Year(), 1, 1, 0, 0, 0, 0, year.Location())
	counts := make(DurationCounts, 12)
	for i := 1; i <= 12; i++ {
		var sum int64
		for _, ety := range etys {
			if ety.Month == int64(i) {
				sum += ety.Total
			}
		}
		month := begin.AddDate(0, i-1, 1)
		counts[i-1] = DurationCount{
			Point: month,
			Count: sum,
		}
	}
	return counts, err
}

func (a *userActive) FiveYearsCount(ctx context.Context, year time.Time) (DurationCounts, error) {
	result := make(DurationCounts, 5)
	for i := 0; i < 5; i++ {
		result[i].Point = time.Now().AddDate(-i, 0, 0)
	}
	row, err := GetAuthDB(ctx).Raw(
		"SELECT sum(total),year from user_active GROUP BY year ORDER BY year desc LIMIT 5").Rows()
	if err != nil {
		return result, err
	}
	for row.Next() {
		var y, total int64
		row.Scan(&total, &y)
		for i := 0; i < 5; i++ {
			if result[i].Point.Year() == int(y) {
				result[i].Count = total
			}
		}
	}
	return result, err
}

func (a *userActive) MaxCount(ctx context.Context) int64 {
	var maxCount int64
	row := GetAuthDB(ctx).Raw("SELECT max(total) from user_active").Row()
	row.Scan(&maxCount)
	return maxCount
}
